#include <vector>
#include <map>
#include <string>
#include <netthumb.h>
#include <SymbolTable.h>

namespace netthumb{

  SymbolTable::SymbolTable()
  {
    _valid = false; // Tabla de simbolos no verificada.
  }

  void
  SymbolTable::insertNewHost(HostI* host, string id)
  {
    _hosts[id] = host;
  }

  void
  SymbolTable::insertNewRouter(RouterI* router, string id)
  {
    _routers[id] = router;
  }

  void
  SymbolTable::insertNewNetwork(NetworkI* network, string id)
  {
    _networks[id] = network;
  }

  map<string, HostI*>&
  SymbolTable::getHosts()
  {
    return _hosts;
  }

  map<string, RouterI*>&
  SymbolTable::getRouters()
  {
    return _routers;
  }

  map<string, NetworkI*>&
  SymbolTable::getNetworks()
  {
    return _networks;
  }

  bool
  SymbolTable::getHostByID(string id, HostI& host)
  {
    if(_hosts.count(id)){
      HostI* allocatedHost = _hosts[id];
      map<string, DeviceI*> devMap = allocatedHost->getDevices();
      host.setDevices(devMap);
      host.setRoute(allocatedHost->getRoute());
      host.setLocation(allocatedHost->getLocation());
      return true;
    }
    return false;
  }

  bool
  SymbolTable::getDevicesByHost(string hostID, map<string, DeviceI*>& devMap)
  {
    if(_hosts.count(hostID)){
      devMap.insert(_hosts[hostID]->getDevices().begin(),
		    _hosts[hostID]->getDevices().end());
      return true;
    }
    return false;
  }

  bool
  SymbolTable::getRouterByID(string id, RouterI& router)
  {
    if(_routers.count(id)){
      RouterI* allocatedRouter = _routers[id];
      map<string, DeviceI*> devMap = allocatedRouter->getDevices();
      router.setDevices(devMap);
      router.setRoute(allocatedRouter->getRoute());
      router.setLocation(allocatedRouter->getLocation());
      return true;
    }
    return false;
  }

  bool
  SymbolTable::getDevicesByRouter(string routerID, map<string, DeviceI*>& devMap)
  {
    if(_routers.count(routerID)){
      devMap.insert(_routers[routerID]->getDevices().begin(),
		    _routers[routerID]->getDevices().end());
      return true;
    }
    return false;
  }

  bool
  SymbolTable::getNetworkByID(string id, NetworkI& network)
  {
    if(_networks.count(id)){
      NetworkI* allocatedNetwork = _networks[id];
      network.populate(allocatedNetwork->getAddress(),
			allocatedNetwork->getTypeID(),
			allocatedNetwork->getMtu(),
			allocatedNetwork->isMulticast(),
			allocatedNetwork->getLocation());
      return true;
    }
    return false;
  }

  string
  SymbolTable::toString()
  {
    string strOut = string("Hosts:\n");
    map<string, HostI*>::iterator it;
    for(it = _hosts.begin(); it != _hosts.end(); it++){
      strOut.append("Host ");
      strOut.append(it->first);
      strOut.append(":\n");
      strOut.append(it->second->toString());
    }

    strOut.append("\nRouters");

    map<string, RouterI*>::iterator it2;
    for(it2 = _routers.begin(); it2 != _routers.end(); it2++){
      strOut.append("Router ");
      strOut.append(it2->first);
      strOut.append(":\n");
      strOut.append(it2->second->toString());
    }

    strOut.append("\nNetworks:");

    map<string, NetworkI*>::iterator it3;
    for(it3 = _networks.begin(); it3 != _networks.end(); it3++){
      strOut.append("Network ");
      strOut.append(it3->first);
      strOut.append(":\n");
      strOut.append(it3->second->toString());
    }

    strOut.append("\n");

    return strOut;
  }

  bool
  SymbolTable::isValid()
  {
    return _valid;
  }
}
